package ypmits.preloader {
	import ypmits.data.basic.DataLoader;
	import ypmits.data.basic.DataLoaderVO;
	import ypmits.setup.EasySetup;
	import ypmits.setup.EasySetupInput;
	import ypmits.utils.ICore;
	import ypmits.utils.SimpleMath;

	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLRequest;

	/**
	 * @author Dave Lenz
	 */
	public class AbstractPreloader extends Sprite implements IPreloader {
		private var _problems : Array = new Array();
		private var _loader : Loader;
		private var _l : DataLoader;
		protected var _core : ICore;
		private var _graphic : DisplayObject;
		private var _coreSWF : String;
		protected var preloads : Array;
		protected var percentage : Number;
		private var _easyinput : EasySetupInput;
		private var disposeaftercomplete : Boolean = false;

		/**
		 * AbstractPreloader provides all the basic functionality for the preloader it's extending.
		 * <b>IMPORTANT:</b>
		 * You've got to provide a '<code>graphic</code>' which implements the IPreloaderGraphic-interface
		 * and a '<code>coreSWF</code>' for it to function, otherwise you'll be thrown an appropriate error
		 * You can also add as much DataLoaderVO's <code>(ypmits.utils.data.basic.vo.DataLoaderVO)</code>
		 * to the preload-array to preload any kind of data of the type '<code>ypmits.utils.data.basic.DataType</code>'.
		 */
		function AbstractPreloader( easyinput : EasySetupInput )
		{
			_easyinput = easyinput;

			addEventListener( Event.ADDED_TO_STAGE, addedToStageHandler );
		}


		private function addedToStageHandler( event : Event ) : void
		{
			removeEventListener( Event.ADDED_TO_STAGE, addedToStageHandler );

			EasySetup.instance.init( this, _easyinput );
			EasySetup.instance.stage.addEventListener( Event.RESIZE, resizeHandler );
			EasySetup.instance.debug = _easyinput.debug;

			init();
		}


		private function resizeHandler( e : Event ) : void
		{
			IPreloaderGraphic( _graphic ).updateDisplayList();
		}


		public function init() : void
		{
			if( !_graphic )
				_problems.push( "ERROR! you should provide a DisplayObject for '_graphic'" );
			if( !_graphic is IPreloaderGraphic )
				_problems.push( "ERROR! _graphic should implement IPreloaderGraphic!" );
			if( !_coreSWF )
				_problems.push( "ERROR! you should provide a value for 'coreSWF'" );

			if( _problems.length > 0 )
				throw new Error( _problems );

			_graphic.alpha = 1;
			_graphic.addEventListener( Event.COMPLETE, initCore );
			addChild( _graphic );

			_loader = new Loader();
			_loader.contentLoaderInfo.addEventListener( Event.COMPLETE, completeHandler );
			_loader.contentLoaderInfo.addEventListener( ProgressEvent.PROGRESS, progressHandler );
			_loader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR, errorHandler );
			_loader.contentLoaderInfo.addEventListener( HTTPStatusEvent.HTTP_STATUS, httpHandler );
			_loader.load( new URLRequest( _coreSWF ) );

			_l = DataLoader.instance;
			_l.addEventListener( Event.COMPLETE, preloadCompleteHandler );
			_l.addEventListener( IOErrorEvent.IO_ERROR, errorHandler );

			IPreloaderGraphic( _graphic ).show();
		}


		protected function progressHandler( e : ProgressEvent ) : void
		{
			percentage = SimpleMath.convertProgressEventToPercentage( e );
			IPreloaderGraphic( _graphic ).percentage = percentage;
			IPreloaderGraphic( _graphic ).updateDisplayList();
		}


		private function errorHandler( e : IOErrorEvent ) : void
		{
		}


		private function httpHandler( e : HTTPStatusEvent ) : void
		{
			if( e.status == 0 ) {
			} else {
				// trace( "AbstractPreloader.httpHandler("+[e.status]+")" );
			}
		}


		protected function completeHandler( e : Event ) : void
		{
			_core = ICore( LoaderInfo( e.currentTarget ).content );

			if( preloads && ( preloads.length > 0 ) ) {
				for (var i : int = 0; i < preloads.length; i++) {
					if( preloads[i] is DataLoaderVO ) {
						_l.preload( DataLoaderVO( preloads[i] ) );
					} else {
						throw new Error( "Error! You should use preloads of the type 'DataLoaderVO' and then use a type like f.i. 'DataType.XML'" );
					}
				}

				_l.load();
			} else {
				preloadCompleteHandler();
			}
		}


		private function preloadCompleteHandler( e : Event = null ) : void
		{
			IPreloaderGraphic( _graphic ).hide();
		}


		public function initCore( e : Event ) : void
		{
			if( _core is ICore ) {
				addChild( _core as DisplayObject );
				_core.build();
				if( disposeaftercomplete ) dispose( );
			} else {
				throw new Error( "Error! The loaded core '" + _coreSWF + "' should implement 'ypmits.utils.core.ICore'" );
			}
		}


		/**
		 * With this setter you can provide a graphic for the preloader.
		 * @param value Displayobject A Displayobject which represents the preloader-graphic
		 */
		public function set graphic( value : DisplayObject ) : void {
			_graphic = value;
		}


		public function get graphic() : DisplayObject {
			return _graphic;
		}


		/**
		 * With this setter you can set the name of the Core
		 * @param value String A name that represents the 'Core' to be loaded (i.e. 'PortfolioCore.swf')
		 * <br><br><b>IMPORTANT:</b><br>
		 * The loaded core should implement 'ypmits.utils.core.ICore'
		 */
		public function set coreSWF( value : String ) : void {
			_coreSWF = value;
		}


		public function get coreSWF() : String {
			return _coreSWF;
		}


		public function dispose( e : Event = null ) : void
		{
			_loader.contentLoaderInfo.removeEventListener( Event.COMPLETE, completeHandler );
			_loader.contentLoaderInfo.removeEventListener( ProgressEvent.PROGRESS, progressHandler );
			_loader.contentLoaderInfo.removeEventListener( IOErrorEvent.IO_ERROR, errorHandler );
			_loader.contentLoaderInfo.removeEventListener( HTTPStatusEvent.HTTP_STATUS, httpHandler );
			_loader = null;

			_graphic.removeEventListener( Event.COMPLETE, initCore );
			removeChild( _graphic );
			_graphic = null;

			_l.removeEventListener( Event.COMPLETE, preloadCompleteHandler );
			_l.removeEventListener( IOErrorEvent.IO_ERROR, errorHandler );
			_l = null;

			EasySetup.instance.stage.removeEventListener( Event.RESIZE, resizeHandler );
		}


		public function set disposeAfterComplete( value : Boolean ) : void {
			this.disposeaftercomplete = value;
		}
	}
}
